package com.lly.tboc.zhouyi.vo

import androidx.room.Entity
import androidx.room.Fts4
import androidx.room.FtsOptions.TOKENIZER_UNICODE61
import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import com.google.gson.annotations.SerializedName
import com.lly.markdown.Block
import com.lly.markdown.Heading
import com.lly.markdown.MarkdownServer
import com.lly.markdown.Text

private fun List<Block>.toPlaintText(): String = fold(StringBuilder()) { builder, block ->
    builder.append(block.toPlaint())
}.toString()

@Entity(tableName = "wenYan")
data class WenYan(
    @PrimaryKey
    val guaId: Int,

    val wenYan: String
)

@Entity(tableName = "gua")
data class Gua(
    @PrimaryKey
    @SerializedName("id")
    val id: Int,
    @SerializedName("name")
    val name: String,
    @SerializedName("outer")
    val outer: String,
    @SerializedName("inner")
    val inner: String,

    @SerializedName("ci")
    val ci: String,
    @SerializedName("xiang")
    val xiang: String?,
    @SerializedName("tuan")
    val tuan: String?,
    @SerializedName("wu")
    var wu: String?
) {
    @Ignore
    @SerializedName("data")
    var data: List<Yao> = emptyList()

    @Ignore
    var wenyan: String = ""
    val yaoViewData: List<com.lly.ui.Yao> by lazy {
        Yao.yaoNames(outer, inner).map { it.toUiYao() }
    }

    fun toDataForString(): String {
        return "## 卦$id: ${name} 上${outer}下${inner}\n### 卦辞:\n ${ci}\n### 彖辞:\n ${tuan}\n### 卦象:\n ${xiang}\n### 感悟:\n ${wu}\n\n"
    }

    companion object {
        //        const val TAG_ID = "卦序"
//        const val TAG_NAME = "卦"
        fun default(guaId: Int): Gua = Gua(guaId, "", "", "", "", "", "", "")
        private val baseInfoRe by lazy {
            "卦(?<id>\\d+): (?<name>\\S+) 上(?<outer>\\S)下(?<inner>\\S)".toRegex()
        }

        fun parse(data: String): Gua {
            val markdownItems = MarkdownServer.parse(data, null)
            var id = 0
            var name = ""
            var outer = ""
            var inner = ""
            var ci = ""
            var tuan = ""
            var xiang = ""
            var wu = ""
            val iterator = markdownItems.iterator()
            while (iterator.hasNext()) {
                when (val markdownItem = iterator.next()) {
                    is Heading -> {
                        if (markdownItem.level == 2) {
                            val text = markdownItem.content.toPlaintText()
                            val groups = baseInfoRe.find(text)!!.groups
                            id = groups["id"]!!.value.toInt()
                            name = groups["name"]!!.value
                            outer = groups["outer"]!!.value
                            inner = groups["inner"]!!.value
                        } else if (markdownItem.level == 3) {
                            val text = markdownItem.content.toPlaintText()
                            val next = (iterator.next() as Text).content.toPlaintText()
                            when (text) {
                                "卦辞:" -> ci = next
                                "彖辞:" -> tuan = next
                                "卦象:" -> xiang = next
                                "感悟:" -> wu = next
                                else -> throw Exception(text + next)
                            }
                        }
                    }

                    else -> throw Exception(markdownItem.toString())
                }
            }
            return Gua(
                id = id,
                name = name,
                outer = outer,
                inner = inner,
                ci = ci.trim(),
                xiang = xiang.trim(),
                tuan = tuan.trim(),
                wu = wu.trim()
            )
        }


        val names = arrayOf("乾", "兑", "离", "震", "巽", "坎", "艮", "坤")

    }
}

@Fts4(contentEntity = Gua::class, tokenizer = TOKENIZER_UNICODE61)
@Entity(tableName = "guafts")
data class GuaFts(
    val name: String,
    val ci: String,
    var wu: String?
)

@Entity(
    tableName = "yao",
    primaryKeys = ["id", "guaId"],
    indices = [Index("guaId")]
)
data class Yao(
    @SerializedName("id")
    val id: Int,
    @SerializedName("guaId")
    var guaId: Int = 0,
    @SerializedName("name")
    val name: String,
    @SerializedName("ci")
    val ci: String,
    @SerializedName("xiang")
    val xiang: String?,
    @SerializedName("wu")
    val wu: String?
) {
    fun toDataForString(): String {
        return "#### 爻名: $name\n##### 爻象:\n$ci\n##### 爻词\n$xiang\n##### 爻感悟:\n$wu\n\n"
    }

    companion object {
        fun generate(guaId: Int, outer: String, inner: String): Array<Yao> {
            val ans = yaoNames(outer, inner)
            if (outer == inner) {
                if (outer == "乾") {
                    ans.add(YaoName.Nine)
                } else if (outer == "坤") {
                    ans.add(YaoName.Six)
                }
            }
            return ans.mapIndexed { i, it -> Yao(i, guaId, it.name(i), "", "", "") }.toTypedArray()
        }

        fun yaoNames(
            outer: String,
            inner: String,
        ): MutableList<YaoName> {
            val ans = mutableListOf<YaoName>()
            for (item in arrayOf(inner, outer)) {
                yaoNames(item, ans)
            }
            return ans
        }

        fun yaoNames(
            singleGua: String,
            ans: MutableList<YaoName>
        ) {
            when (singleGua) {
                "乾" -> {
                    for (i in 0..2) {
                        ans.add(YaoName.Nine)
                    }
                }

                "坤" -> {
                    for (i in 0..2) {
                        ans.add(YaoName.Six)
                    }
                }

                "艮" -> {
                    ans.add(YaoName.Six)
                    ans.add(YaoName.Six)
                    ans.add(YaoName.Nine)
                }

                "震" -> {
                    ans.add(YaoName.Nine)
                    ans.add(YaoName.Six)
                    ans.add(YaoName.Six)
                }

                "坎" -> {
                    ans.add(YaoName.Six)
                    ans.add(YaoName.Nine)
                    ans.add(YaoName.Six)
                }

                "离" -> {
                    ans.add(YaoName.Nine)
                    ans.add(YaoName.Six)
                    ans.add(YaoName.Nine)
                }

                "巽" -> {
                    ans.add(YaoName.Six)
                    ans.add(YaoName.Nine)
                    ans.add(YaoName.Nine)
                }

                "兑" -> {
                    ans.add(YaoName.Nine)
                    ans.add(YaoName.Nine)
                    ans.add(YaoName.Six)
                }
            }
        }
    }
}

enum class YaoName(private val lastName: String) {
    Nine("九"),
    Six("六");

    fun name(id: Int) = when (id) {
        0 -> "初${lastName}"
        5 -> "上${lastName}"
        6 -> "用${lastName}"
        1 -> "${lastName}二"
        2 -> "${lastName}三"
        3 -> "${lastName}四"
        4 -> "${lastName}五"
        else -> throw IndexOutOfBoundsException("id 不在0～6之间")
    }

    fun isYang() = this == Nine
    fun toUiYao() = com.lly.ui.Yao(isYang())
}

@Fts4(contentEntity = Yao::class, tokenizer = TOKENIZER_UNICODE61)
@Entity(tableName = "yaofts")
data class YaoFts(
    val id: Int,
    var guaId: Int = 0,
    val name: String,
    val ci: String,
    var wu: String?
)

data class GuaDatas(
    val count: Int,
    val hasNext: Int,
    val data: List<Gua>
)

